package com.ruoyi.system.service.impl;

import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.uuid.Seq;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.RemoteFileService;
import com.ruoyi.system.api.domain.File;
import com.ruoyi.system.api.domain.FileData;
import com.ruoyi.system.api.domain.FileObject;
import com.ruoyi.system.domain.FileAuth;
import com.ruoyi.system.domain.FileRecord;
import com.ruoyi.system.api.domain.SysUserRole;
import com.ruoyi.system.mapper.FileDataMapper;
import com.ruoyi.system.mapper.FileMapper;
import com.ruoyi.system.service.IFileService;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 附件Service业务层处理
 *
 * @author ruoyi
 * @date 2023-02-22
 */
@Service
public class FileServiceImpl implements IFileService {

    @Autowired
    private FileMapper fileMapper;

    @Autowired
    private FileDataMapper fileDataMapper;

    @Autowired
    private RemoteFileService remoteFileService;

    /**
     * 查询附件
     *
     * @param fileId 附件主键
     * @return 附件
     */
    @Override
    public File selectFileByFileId(Long fileId) {
        return fileMapper.selectFileByFileId(fileId);
    }

    @Override
    public List<File> selectFileListByGroupId(Long groupId, String typeIds) {
        File file = new File();
        file.setGroupId(groupId);
        file.setTypeIds(typeIds);
        return fileMapper.selectFileList(file);
    }

    @Override
    public FileData selectFileDataBYDataId(Long dataId) {
        return fileDataMapper.selectFileDataByDataId(dataId);
    }

    @Override
    public List<FileData> selectFileDataListByGroupId(Long groupId, String fileTypes) {
        FileData fileData = new FileData();
        fileData.setOrgId(SecurityUtils.getLoginUser().getSysUser().getOrgId());
        fileData.setGroupId(groupId);
        fileData.setFileTypes(fileTypes);
        List<FileData> fileDataList = fileDataMapper.selectFileDataList(fileData);
        return fileDataList;
    }

    /**
     * 查询附件列表
     *
     * @param file 附件
     * @return 附件
     */
    @Override
    public List<File> selectFileList(File file) {
        return fileMapper.selectFileList(file);
    }

    @Override
    public List<FileData> selectFileDataList(FileData fileDate) {
        return fileDataMapper.selectFileDataList(fileDate);
    }


    /**
     * 新增附件
     *
     * @param file 附件
     * @return 结果
     */
    @Override
    public int insertFile(File file) {
        if(file.getFileOrgId() != null){
            file.setOrgId(file.getFileOrgId());
        }
        if (file.getFileId() == null) {
            file.setFileId(Seq.getSeqId());
            return fileMapper.insertFile(file);
        }
        return fileMapper.updateFile(file);
    }

    @Transactional
    @Override
    public boolean saveFile(Long groupId, Integer typeId, List<Long> fileIds) {
        if (groupId == null || typeId == null) return false;
        File queryFile = new File();
        queryFile.setOrgId(SecurityUtils.getOrgId());
        queryFile.setGroupId(groupId);
        queryFile.setTypeId(typeId);
        if (StringUtils.isEmpty(fileIds)) {//当前操作要保存的附件为空，则根据条件把当前组内的附件都删除。
            fileMapper.deleteFile(queryFile);
            return true;
        }
        //筛选出要删除的附件。
        List<File> fileList = fileMapper.selectFileList(queryFile);
        List<Long> delFileIds = new ArrayList<Long>();
        if (StringUtils.isNotEmpty(fileList)) {
            for (File tempFile : fileList) {
                if (!fileIds.contains(tempFile.getFileId()))//从库里查询出的附件没有在此次要保存的列表中，说明当前附件需要删除，先放到list中，稍后统一删除。
                    delFileIds.add(tempFile.getFileId());
            }
        }
        if (delFileIds.size() > 0) {//此列表中是需要删除的附件。
            fileMapper.deleteFileByFileIds(delFileIds.toArray(new Long[delFileIds.size()]));
        }
        File file = new File();
        for (Long fileId : fileIds) {
            file.setFileId(fileId);
            file.setGroupId(groupId);
            file.setTypeId(typeId);
            fileMapper.updateFile(file);
        }
        return true;
    }

    @Transactional
    @Override
    public boolean saveFileDataList(FileObject fileObject) {
        if (fileObject == null) return true;
        if (StringUtils.isNotEmpty(fileObject.getDelFileList())) {
            FileData delFileData = new FileData();
            delFileData.setOrgId(SecurityUtils.getLoginUser().getSysUser().getOrgId());
            for (String delGroupId : fileObject.getDelFileList()) {
                String[] delGroupIds = delGroupId.split("\\|");
                delFileData.setGroupId(Long.parseLong(delGroupIds[0]));
                delFileData.setFileType(Integer.parseInt(delGroupIds[1]));
                fileDataMapper.deleteFileData(delFileData);
            }
        }
        List<FileData> fileDataList = fileObject.getFileDataList();
        if (StringUtils.isNotEmpty(fileDataList)) {
            for (FileData fileData : fileDataList) {
                fileData.setOrgId(SecurityUtils.getLoginUser().getSysUser().getOrgId());
                fileData.setCreateUserId(SecurityUtils.getUserId());
                fileData.setCreateUserName(SecurityUtils.getUsername());
                fileData.setDataId(Seq.getId());
                fileDataMapper.insertFileData(fileData);
                if (StringUtils.isEmpty(fileData.getFileList())) continue;
                for (File file : fileData.getFileList()) {
                    file.setTypeId(fileData.getFileType());
                    file.setGroupId(fileData.getDataId());
                    fileMapper.updateFile(file);
                }
            }
        }
        return true;
    }

    @Transactional
    @Override
    public boolean saveFileData(FileData fileData) {
        List<File> fileList = fileData.getFileList();
        if (fileData.getDataId() == null) {//新增文件数据
            fileData.setOrgId(SecurityUtils.getLoginUser().getSysUser().getOrgId());
            fileData.setCreateUserId(SecurityUtils.getUserId());
            fileData.setCreateUserName(SecurityUtils.getLoginUser().getSysUser().getNickName());
            fileData.setDataId(Seq.getId());
            fileDataMapper.insertFileData(fileData);
            if (StringUtils.isNotEmpty(fileList)) {
                for (File file : fileList) {
                    file.setTypeId(fileData.getFileType());
                    file.setGroupId(fileData.getDataId());
                    if (fileMapper.updateFile(file) == 0) {
                        System.out.println("文件上传失败");
                    }
                }
            }
        } else {//更新文件信息
            List<Long> fileIds = fileList.stream().map(File::getFileId).collect(Collectors.toList());
            fileDataMapper.updateFileData(fileData);
            return saveFile(fileData.getDataId(), fileData.getFileType(), fileIds);
        }
        return true;
    }

    /**
     * 批量删除附件
     *
     * @param fileIds 需要删除的附件主键
     * @return 结果
     */
    @Override
    public int deleteFileByFileIds(Long[] fileIds) {
        return fileMapper.deleteFileByFileIds(fileIds);
    }

    /**
     * 删除附件信息
     *
     * @param fileId 附件主键
     * @return 结果
     */
    @Override
    public int deleteFileByFileId(Long fileId) {
        return fileMapper.deleteFileByFileId(fileId);
    }

    @Transactional
    @Override
    public int deleteFileDataByDataId(String[] dataIds) {
        fileMapper.deleteFileByGroupIds(dataIds);
        return fileDataMapper.deleteFileDataByDataIds(dataIds);
    }

    @Override
    public int saveFile(File file) {
        if (file.getFileId() == null) {
            throw new ServiceException("请先上传附件");
        }
        return fileMapper.updateFile(file);
    }

    @Override
    public int addFileAuth(FileAuth fileAuth) {
        if (StringUtils.isEmpty(fileAuth.getRoleIds()) || StringUtils.isEmpty(fileAuth.getDataIds())) {
            throw new ServiceException("请选择角色或者文件");
        }
        int i = fileDataMapper.selectAuthIsExist(fileAuth);
        if (i > 0) {
            throw new ServiceException("当前文件的这些角色权限已经配置");
        }
        for (Long dataId : fileAuth.getDataIds()) {
            for (Long roleId : fileAuth.getRoleIds()) {
                FileAuth insertFileAuth = new FileAuth();
                insertFileAuth.setOrgId(SecurityUtils.getOrgId());
                insertFileAuth.setDataId(dataId);
                insertFileAuth.setRoleId(roleId);
                if (fileDataMapper.addFileAuth(insertFileAuth) == 0) {
                    throw new ServiceException("插入数据失败");
                }
            }
        }
        return 1;
    }

    @Override
    public List<FileRecord> selectFileRecordList(FileRecord fileRecord) {
        return fileDataMapper.selectFileRecordList(fileRecord);
    }

    @Transactional
    @Override
    public int splitFileList(File file) {
        Long[] newGroupIds = file.getGroupIds();
        if(file.getGroupId() == null || file.getGroupIds() == null) {
            throw new ServiceException("分割文件失败！");
        }
        List<File> fileList = fileMapper.selectFileList(file);
        if(fileList.size() == 0) return 1;
        Long orgId = SecurityUtils.getOrgId();
        for(File orgFile : fileList){
            for(Long newGroupId : newGroupIds){
                orgFile.setFileId(Seq.getSeqId());
                orgFile.setGroupId(newGroupId);
                orgFile.setOrgId(orgId);
                if(fileMapper.insertFile(orgFile) == 0){
                    throw new ServiceException("分割文件失败！");
                }
            }
        }
        if(fileMapper.deleteFileByGroupId(file.getGroupId()) == 0){
            throw new ServiceException("分割文件失败！");
        }
        return 1;
    }

    @Override
    @Transactional
    public String download(File file, HttpServletResponse response) throws IOException {
        String errorMsg = null;
        Long dataId = file.getGroupId();
        List<FileAuth> fileAuthList = fileDataMapper.selectFileAuthList(dataId);
        if (fileAuthList.size() == 0) {
            errorMsg = "当前文件没有配置权限,无法下载";
            // throw new ServiceException("当前文件没有配置权限,无法下载");
            return errorMsg;
        }
        Long[] roleIds = fileAuthList.stream().map(FileAuth::getRoleId).toArray(Long[]::new);
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setRoleIds(roleIds);
        sysUserRole.setUserId(SecurityUtils.getUserId());
        List<SysUserRole> sysUserRoleList = fileDataMapper.selectUserRoleList(sysUserRole);
        if (sysUserRoleList.size() == 0) {
            errorMsg = "用户: " + SecurityUtils.getLoginUser().getSysUser().getNickName() + "没有这个文件的下载权限";
            return errorMsg;
            // throw new ServiceException("用户:" + SecurityUtils.getLoginUser().getSysUser().getNickName() + "没有这个文件的下载权限");
        }
        R<byte[]> fileResult = remoteFileService.download("", file.getFilePath());
        if (fileResult.getCode() != 200) {
            errorMsg = "下载文件失败，请联系管理员";
            return errorMsg;
            // throw new ServiceException("下载文件失败，请联系管理员");
        }
        // 添加文件下载记录
        FileRecord fileRecord = new FileRecord();
        fileRecord.setRecordId(Seq.getSeqId());
        fileRecord.setRecordUserId(SecurityUtils.getUserId());
        fileRecord.setRecordUserName(SecurityUtils.getLoginUser().getSysUser().getNickName());
        fileRecord.setDataId(dataId);
        fileRecord.setOrgId(SecurityUtils.getOrgId());
        if (fileDataMapper.insertFileRecord(fileRecord) == 0) {
            errorMsg = "添加文件下载记录失败,请联系管理员";
            return errorMsg;
            // throw new ServiceException("添加文件下载记录失败,请联系管理员");
        }
        byte[] fileData = fileResult.getData();
        response.reset();
        response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getFileName() + "\"");
        response.addHeader("Content-Length", "" + fileData.length);
        response.setContentType("application/octet-stream; charset=UTF-8");
        IOUtils.write(fileData, response.getOutputStream());
        return null;
    }

    @Override
    public int removeFile(Long fileId) {
        return fileMapper.deleteFileByFileId(fileId);
    }

    @Override
    public int deleteFileByProcInsId(File file){
        return fileMapper.deleteFileByProcInsId(file);
    }

}
